//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.1.1
#include "flash_bsp.h"

/*预留读写flash结构体*/
typedef struct
{
    volatile unsigned int Data[1];
}WHT_Flash_Data_t;


/*擦除内部FLASH*/
ErrorStatus WHT_Flash_BSP_Erase_And_Check(unsigned int start_page, unsigned int page_count)
{
    unsigned int Page_Address = start_page * FLASH_PAGE_SIZE + FLASH_BASE_ADDR;
    FLASH_Status status = FLASH_COMPLETE;

    /*擦除*/
    FLASH_Unlock();//Flash解锁
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//清空所有标志位
    for(unsigned int i = 0; i < page_count; i++)//页擦除
    {
#ifdef WWDG_FUNC_ENABLE
        extern WHT_WWDG_Config_t WWDG_Config;
        WHT_WWDG_BSP.WHT_Reset_Start_Time(&WWDG_Config);
#endif /*WWDG_FUNC_ENABLE*/
        status = FLASH_ErasePage(Page_Address + i * FLASH_PAGE_SIZE);
        if (status != FLASH_COMPLETE)
            break;
	}
    FLASH_Lock();//Flash上锁

    /*查空*/
    if (status == FLASH_COMPLETE)
    {
        for (unsigned int i = 0; i < page_count * FLASH_PAGE_SIZE / sizeof(unsigned int); i++)
        {
            if (((volatile unsigned int*)Page_Address)[i] != 0xffffffff)
            {
                status = FLASH_ERROR_PG;
                break;
            }
        }
    }
    return (status == FLASH_COMPLETE ? SUCCESS : ERROR);
}

/*读取内部FLASH*/
void WHT_Flash_BSP_Read(unsigned int start_addr, unsigned char* out_buf, unsigned int size)
{
    unsigned int Word_Count = size / sizeof(unsigned int);
    unsigned char End_Count = size % sizeof(unsigned int);

    start_addr += FLASH_BASE_ADDR;
    for (unsigned int i = 0; i < Word_Count; i++)
    {
        ((unsigned int*)out_buf)[i] = ((volatile unsigned int*)start_addr)[i];
    }
    while(End_Count--)
    {
        out_buf[size - End_Count] = *((volatile unsigned char*)(start_addr + size - End_Count));
    }
}

/*写入内部FLASH*/
ErrorStatus WHT_Flash_BSP_Write(unsigned int start_addr, const unsigned char* in_buf, unsigned int size)
{
    FLASH_Status status = FLASH_COMPLETE;
    unsigned int Word_Count = size / sizeof(unsigned int);
    unsigned char End_Count = size % sizeof(unsigned int);

    start_addr += FLASH_BASE_ADDR;
    /*烧录*/
    FLASH_Unlock();//Flash解锁   
    for (unsigned int i = 0; i < Word_Count; i++)
    {
        status = FLASH_ProgramWord(start_addr, ((const unsigned int*)in_buf)[i]);
        if (status != FLASH_COMPLETE)
            break;
        start_addr += sizeof(unsigned int);
    }
    if (End_Count && (status == FLASH_COMPLETE))
    {
        unsigned int End_Data = ((const unsigned int*)in_buf)[Word_Count] | (0xffffffff << (End_Count * 8));//高位数据设置0xff

        status = FLASH_ProgramWord(start_addr, End_Data);
    }
    FLASH_Lock();//Flash上锁

    /*校验*/
    if (status == FLASH_COMPLETE)
#if 0
    {//芯片自带CRC32校验，参与校验数据不全，4字节对齐
        unsigned int CRC32_Src;
        unsigned int CRC32_Dst;

        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
        CRC_ResetDR();
        CRC32_Src = CRC_CalcBlockCRC((unsigned int*)in_buf, Word_Count);

        start_addr -= Word_Count * sizeof(unsigned int);
        CRC_ResetDR();
        CRC32_Dst = CRC_CalcBlockCRC((unsigned int*)start_addr, Word_Count);
        if (CRC32_Src != CRC32_Dst)
            status = FLASH_ERROR_PG;
    }
#else
    {//手动全校验
        start_addr -= Word_Count * sizeof(unsigned int);
        for (unsigned int i = 0; i < size; i++)
        {
            if (((volatile unsigned char*)start_addr)[i] != in_buf[i])
            {
                status = FLASH_ERROR_PG;
                break;
            }
        }
    }
#endif
    return (status == FLASH_COMPLETE ? SUCCESS : ERROR);
}
